﻿// Demo1.cpp : 定义应用程序的入口点。
//


#include "Demo1.h"


void Demo1::OnResize() {
	float aspect = (float)GetWidth() / GetHeight();
	Matrix4x4 proj = Matrix4x4::CreatePerspectiveFovLH(Deg2Rad(60), aspect, 1.0f, 1000.0f);
	m_mvpBufferData.projMat = proj.Transpose();
}
void Demo1::OnInit() {
	auto graphics = Graphics::GetInstance();
	auto device = graphics->GetDevice();
	auto ctx = graphics->GetDeviceContext();

	// 创建几个 meshData
	m_meshData0.InitFromIndexedTriangleList(Cube::Make());

	Vec4 color(1, 0, 0, 1);
	m_meshData1.InitFromIndexedTriangleList(Cone::Make(), color);

	// 创建几套  vs ps 
	m_vertexShader0 = std::make_shared<VertexShader>("first.hlsl", "VS_Main");
	m_pixelShader0 = std::make_shared<PixelShader>("first.hlsl", "PS_Main");

	m_vertexShader1 = std::make_shared<VertexShader>("second.hlsl", "VS_Main");
	m_pixelShader1 = std::make_shared<PixelShader>("second.hlsl", "PS_Main");

	// 创建一些 objects
	int count0 = 0;
	int count1 = 0;
	for (size_t i = 0; i < 100; i++)
	{
		// 随机
		auto obj = std::make_shared<GameObject>();
		int r = RandomInt(0, 2);
		if (r > 0)
		{
			count0++;
			// 用第一套着色器
			obj->SetShader(m_vertexShader0.get(), m_pixelShader0.get());
			obj->SetMesh_Pos(m_meshData0);
		}
		else {
			count1++;
			obj->SetShader(m_vertexShader1.get(), m_pixelShader1.get());
			obj->SetMesh_PosColor(m_meshData1);
		}

		float x = RandomFloat(-20, 20);
		float y = RandomFloat(-5, 5);
		float z = RandomFloat(-20, 20);
		obj->GetTransform().SetLocalPosition(x, y, z);

		m_objs.push_back(obj);
	}
	std::cout << "count0:" << count0 << std::endl;
	std::cout << "count1:" << count1 << std::endl;

	// 创建 constant buffer
	{
		// mvp buffer
		D3D11_BUFFER_DESC cbd = {};
		cbd.Usage = D3D11_USAGE_DYNAMIC;
		cbd.ByteWidth = sizeof(MVPBuffer);
		cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		cbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		D_HRESULT(device->CreateBuffer(&cbd, nullptr, &m_mvpBuffer));

		// ucolor buffer
		m_color.Set(1, 1, 0, 1);
		cbd.ByteWidth = sizeof(Vec4);
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = &m_color;
		D_HRESULT(device->CreateBuffer(&cbd, &sd, &m_uColorBuffer));

		// 绑定 VS PS
		// 第1套
		ctx->VSSetShader(m_vertexShader0->GetDxVertexShader(), nullptr, 0);
		ctx->VSSetConstantBuffers(0, 1, m_mvpBuffer.GetAddressOf());
		ctx->PSSetShader(m_pixelShader0->GetDxPixelShader(), nullptr, 0);
		ctx->PSSetConstantBuffers(1, 1, m_uColorBuffer.GetAddressOf());

		// 第2套
		ctx->VSSetShader(m_vertexShader1->GetDxVertexShader(), nullptr, 0);
		ctx->VSSetConstantBuffers(0, 1, m_mvpBuffer.GetAddressOf());
		ctx->PSSetShader(m_pixelShader1->GetDxPixelShader(), nullptr, 0);

		// buffer data
		float aspect = (float)GetWidth() / GetHeight();
		Matrix4x4 view = Matrix4x4::CreateTranslation(0, 0, 5);
		Matrix4x4 proj = Matrix4x4::CreatePerspectiveFovLH(Deg2Rad(60), aspect, 1.0f, 1000.0f);

		m_mvpBufferData.worldMat.SetIdentity();
		m_mvpBufferData.projMat = proj.Transpose();
		m_mvpBufferData.viewMat = view.Transpose();
	}
}
void Demo1::OnInput() {}
void Demo1::OnUpdate() {

	static float pitch = 0, yaw = 0, roll = 0;
	pitch += 0.01f;
	yaw += 0.02f;
	roll += 0.03f;

	for (auto& obj : m_objs) {
		obj->GetTransform().SetLocalRotation(Quaternion::CreateFromRollPitchYaw(roll, pitch, yaw));
		obj->Update();
	}
}
void Demo1::OnFrame() {

	auto graphics = GetGraphics();
	auto ctx = graphics->GetDeviceContext();
	graphics->ClearBuffer();

	// 更新 constant buffer
	/*ComPtr<ID3D11Buffer> dxConstantBuffer;
	ctx->VSGetConstantBuffers(0, 1, &dxConstantBuffer);*/

	// 绘制物体
	for (auto& obj : m_objs) {

		m_mvpBufferData.worldMat = obj->GetTransform().GetLocalMatrix().Transpose();
		D3D11_MAPPED_SUBRESOURCE mappedData;
		D_HRESULT(ctx->Map(m_mvpBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
		memcpy_s(mappedData.pData, sizeof(MVPBuffer), &m_mvpBufferData, sizeof(MVPBuffer));
		ctx->Unmap(m_mvpBuffer.Get(), 0);

		obj->Draw();
	}
}
void Demo1::OnTerminate() {

}
void Demo1::OnGUI() {

	static bool show_demo_window = false;
	static bool show_another_window = false;
	static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

	// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
	if (show_demo_window)
		ImGui::ShowDemoWindow(&show_demo_window);

	// 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
	{
		static float f = 0.0f;
		static int counter = 0;

		ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.

		ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
		ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
		ImGui::Checkbox("Another Window", &show_another_window);

		ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
		ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

		if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
			counter++;
		ImGui::SameLine();
		ImGui::Text("counter = %d", counter);

		ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
		ImGui::End();
	}

	// 3. Show another simple window.
	if (show_another_window)
	{
		ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
		ImGui::Text("Hello from another window!");
		if (ImGui::Button("Close Me"))
			show_another_window = false;
		ImGui::End();
	}
}


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	WinFunc::CreateConsole();

	// TODO: 在此处放置代码。
	Demo1 myApp;
	myApp.Init(hInstance, 800, 640, "demo1");
	myApp.StartMainLoop();
	return 0;
}


